package org.third.integration.vault.imp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.third.common.SS_CONSTANT;
import org.third.common.utils.StreamUtils;
import org.third.integration.vault.AppRoleExtend;
import org.third.integration.vault.VaultBinClient;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.util.Arrays;

@Service
public class VaultBinClientImp implements VaultBinClient {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	private static final int SUCCESS = 0;

	@Override
	public String createRoleId(String vaultNamespace, String appRole) throws Exception {

		logger.info("Going to generate role id for namespace [{}], app role [{}]", vaultNamespace, appRole);
		String[] commands = { SS_CONSTANT.VAULT_GEN_ROLEID_BIN, vaultNamespace, appRole };
		String result = null;
		Process p = Runtime.getRuntime().exec(commands);
		p.waitFor();
		InputStream in = null;
		String scriptResults = "";
		try {
			in = new BufferedInputStream(p.getInputStream());
			scriptResults = StreamUtils.streamToString(in);
		} catch (Exception e) {
			logger.info("read file erorr!");
		} finally {
			if (in != null) {
				in.close();
			}
		}

		logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_GEN_ROLEID_BIN, scriptResults);

		if (p.exitValue() == SUCCESS) {
			if (scriptResults.startsWith("APPROLE_ID=")) {
				result = scriptResults.substring("APPROLE_ID=".length());
			} else {
				throw new Exception(String.format("Failed to execute command %s, can't parse APPROLE_ID in %s",
						SS_CONSTANT.VAULT_GEN_ROLEID_BIN, scriptResults));
			}
		} else {
			throw new Exception(String.format("Failed to execute command %s, message: %s",
					SS_CONSTANT.VAULT_GEN_ROLEID_BIN, scriptResults));
		}

		return result;
	}

	@Override
	public int storeSecret(String vaultNamespace, String appRole, String roleId, String secretKey, String secretValue)
			throws Exception {

		logger.info("Going to save secret for namespace [{}], app role[{}]", vaultNamespace, appRole);
		String[] commands = { SS_CONSTANT.VAULT_SAVE_SECRET_BIN, vaultNamespace, appRole, roleId, secretKey,
				secretValue };

		Process p = Runtime.getRuntime().exec(commands);
		p.waitFor();
		InputStream in = null;
		String scriptResults = "";
		try {
			in = new BufferedInputStream(p.getInputStream());
			scriptResults = StreamUtils.streamToString(in);
		} catch (Exception e) {
			logger.info("read file erorr!");
		} finally {
			if (in != null) {
				in.close();
			}
		}
		logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_SAVE_SECRET_BIN, scriptResults);
		if (p.exitValue() != SUCCESS) {
			String[] commandsExceptValue = { SS_CONSTANT.VAULT_SAVE_SECRET_BIN, vaultNamespace, appRole, roleId,
					secretKey };
			logger.error(String.format("Failed to execute script \"%s\", message: %s",
					Arrays.toString(commandsExceptValue), scriptResults));
			return p.exitValue();
		}
		return p.exitValue();
	}

	@Override
	public String getSecret(String secretKey) throws Exception {

//		logger.info("Going to get value for vault secret [{}]", secretKey);
		String[] commands = { SS_CONSTANT.VAULT_GET_SECRET_BIN, secretKey };

		Process p = Runtime.getRuntime().exec(commands);
		p.waitFor();
		InputStream in = null;
		String scriptResults = "";
		try {
			in = new BufferedInputStream(p.getInputStream());
			scriptResults = StreamUtils.streamToString(in);
		} catch (Exception e) {
			logger.info("read file erorr!");
		} finally {
			if (in != null) {
				in.close();
			}
		}
//		logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_GET_SECRET_BIN, scriptResults);
		String vaultValue = null;
		if (p.exitValue() == SUCCESS) {
			if (scriptResults.startsWith("PASS=")) {
				vaultValue = scriptResults.substring("PASS=".length());
			} else {
				logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_GET_SECRET_BIN, scriptResults);
				throw new Exception(String.format("Failed to execute command %s, can't parse PASS in %s",
						SS_CONSTANT.VAULT_GET_SECRET_BIN, scriptResults));
			}
		} else {
			logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_GET_SECRET_BIN, scriptResults);
			throw new Exception(String.format("Failed to execute script \"%s\", message: %s", Arrays.toString(commands),
					scriptResults));
		}

		return vaultValue;
	}

	@Override
	public String createRoleId(String vaultNamespace, AppRoleExtend appRoleExtend) throws Exception {
		String appRole = appRoleExtend.getAppRole();

		String readOnlyRoles = (appRoleExtend.getReadOnlyRoles() == null || "".equals(appRoleExtend.getReadOnlyRoles()))
				? ("null")
				: appRoleExtend.getReadOnlyRoles().toString();

		String readWriteRoles = (appRoleExtend.getReadWriteRoles() == null
				|| "".equals(appRoleExtend.getReadWriteRoles().toString())) ? ("null")
						: appRoleExtend.getReadWriteRoles().toString();

		logger.info("Going to generate role id for namespace [{}], app role [{}]", vaultNamespace, appRole,
				readWriteRoles, readOnlyRoles);

		StringBuffer sb = new StringBuffer(SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN);
		sb.append(" " + vaultNamespace);
		sb.append(" " + appRole);
		sb.append(" " + readWriteRoles);
		sb.append(" " + readOnlyRoles);
		// String[] commands = {SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN,sb.toString()};
		String[] commands = { SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, vaultNamespace, appRole, readWriteRoles,
				readOnlyRoles };
		// String[] commands =
		// {SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN,vaultNamespace,appRole,readWriteRoles+"
		// \"","\""+readOnlyRoles};
		logger.debug("commands:" + sb.toString());

		Process p = Runtime.getRuntime().exec(commands);
		p.waitFor();
		InputStream in = null;
		String scriptResults = "";
		try {
			in = new BufferedInputStream(p.getInputStream());
			scriptResults = StreamUtils.streamToString(in);
		} catch (Exception e) {
			logger.info("read file erorr!");
		} finally {
			if (in != null) {
				in.close();
			}
		}
		logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, scriptResults);
		String result = "ERROR";
		if (p.exitValue() == SUCCESS) {
			result = "SUCCESS";
		} else {
			throw new Exception(String.format("Failed to execute command %s, message: %s",
					SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, scriptResults));
		}
		return result;
	}

	@Override
	public String createRoleId(String vaultNamespace, AppRoleExtend appRoleExtend, String extendNameSpace)
			throws Exception {
		String appRole = appRoleExtend.getAppRole();
		String readOnlyRoles = (appRoleExtend.getReadOnlyRoles() == null || "".equals(appRoleExtend.getReadOnlyRoles())
		// )?("\""+"\""):appRoleExtend.getReadOnlyRoles().toString();
		) ? ("null") : appRoleExtend.getReadOnlyRoles().toString();

		String readWriteRoles = (appRoleExtend.getReadWriteRoles() == null
				|| "".equals(appRoleExtend.getReadWriteRoles().toString())
		// )?("\""+"\""):appRoleExtend.getReadWriteRoles().toString();
		) ? ("null") : appRoleExtend.getReadWriteRoles().toString();

		logger.debug(
				"Going to generate role id for namespace [{}], app role [{}],readWriteRoles [{}],readOnlyRoles [{}]",
				vaultNamespace, appRole, readWriteRoles, readOnlyRoles);

		StringBuffer sb = new StringBuffer(SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN);
		sb.append(" " + vaultNamespace);
		sb.append(" " + appRole);
		sb.append(" " + readWriteRoles);
		sb.append(" " + readOnlyRoles);
		sb.append(" " + extendNameSpace);
		logger.debug("commands:" + sb.toString());
		// String updateRoleId demo1 rwall readWriteRoles readOnlyRoles 1
		// String[] commands = {SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN,sb.toString()};
		String[] commands = { SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, vaultNamespace, appRole, readWriteRoles,
				readOnlyRoles, extendNameSpace };
		Process p = Runtime.getRuntime().exec(commands);
		p.waitFor();
		String scriptResults = "";
		try {
			scriptResults = StreamUtils.streamToString(p.getInputStream());
		} catch (Exception e) {
			logger.info("read file erorr!");
		}
		logger.debug("[{}] results: [{}]", SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, scriptResults);
		String result = "ERROR";
		if (p.exitValue() == SUCCESS) {
			result = "SUCCESS";
		} else {
			throw new Exception(String.format("Failed to execute command %s, message: %s",
					SS_CONSTANT.VAULT_UPDATE_ROLEID_BIN, scriptResults));
		}
		return result;
	}

}
